#include "Page.hpp"
#include "String.hpp"

#include <vector>
#include <cctype>
#include <algorithm>
#include <cassert>

#include <iostream>

using namespace std;

Page::Page():mLenContent(0), mConnectionStatus(false) {}

bool
Page::ParseHeaderInfo()
{
    /// @todo parse the status, small than 206 or something
    this->ParseContentLength();
    return true;
}


// could rewrite to automation function
bool
Page::ParseHyperLinks()
{
    bool status = true;
    // only handle <a href="...">
    if (!this->mContent.empty()) {
        string::size_type pos_url_begin = 0;
        string::size_type pos_url_end = 0;
        const string delims(" #>");
        pos_url_begin = String::FindCase(mContent, "<a href=");
        pos_url_end   = mContent.find_first_of(delims, pos_url_begin + sizeof("<a href="));
//         std::cout << pos_url_begin << endl
//                   << pos_url_end << endl;
        while (pos_url_begin != string::npos &&
               pos_url_end   != string::npos) {
            // extract all url
            pos_url_begin += sizeof("<a href=") - 1;
            assert(pos_url_end > pos_url_begin);

            string url_tmp = mContent.substr(pos_url_begin,
                                             pos_url_end - pos_url_begin);
            String::EraseStr(url_tmp, "\"");
            String::EraseStr(url_tmp, "'");

            if (!url_tmp.empty()) {
                if (url_tmp.substr(0, 7) != "http://") {
                    // supplement the url
                    string::size_type pos;
                    pos = mOrginUrl.rfind("/");
                    if (pos > 7) {
                        url_tmp = mOrginUrl.substr(0, pos+1) + url_tmp;
                    } else if (pos != string::npos) {
                        url_tmp = mOrginUrl + "/" + url_tmp;
                    } else {
                        cerr << "\tError: Invalid url " << mOrginUrl << endl;
                    }
                }
                mUrlFromPage.push_back(url_tmp);
            }
            pos_url_begin = String::FindCase(mContent, "<a href=", pos_url_end);
            pos_url_end   = mContent.find_first_of(delims, pos_url_begin + sizeof("<a href="));
        }
    } else {
        status = false;
    }
    return status;
}

int
Page::SetOrginUrl(const string& crUrl)
{
    this->mOrginUrl = crUrl;
    return this->mOrginUrl.length();
}

int
Page::SetHeader(const string& crHeader)
{
    mHeader = crHeader;
    String::Str2Lower(mHeader);
    return mHeader.length();
}

int
Page::SetContent(const string& crContent)
{
    mContent = crContent;
    return mContent.length();
}

void
Page::ParseContentLength()
{
    assert(!mHeader.empty());

    string::size_type pos = mHeader.find("content-length:");
    if (pos != string::npos) {
        mLenContent =
            atoi(mHeader.substr(pos+sizeof("content-length:")).c_str());
    }
}

void
Page::ParseConnectionStatus()
{
    assert(!mHeader.empty());

    string::size_type pos, pos_end;
    pos = mHeader.find("connection: ");
    pos_end = mHeader.find("\r\n", pos);

    if (pos != string::npos && pos_end != string::npos) {
        if (mHeader.substr(pos, pos_end - pos) == "keep-alive") {
            mConnectionStatus = true;
        }
    }
}

string
Page::GetOrginUrl() const
{
    return mOrginUrl;
}

string
Page::GetHeader() const
{
    return mHeader;
}

string
Page::GetContent() const
{
    return mContent;
}

int
Page::GetContentLength() const
{
    return mLenContent;
}

bool
Page::GetConnectionStatus() const
{
    return mConnectionStatus;
}

vector<string>
Page::GetUrlFromPage() const
{
    return mUrlFromPage;
}
